package com.service.order;

import com.domain.HttpResponse;
import com.domain.ex.BizException;
import com.domain.ex.Codes;
import com.domain.myenum.DeliveryTypeEnum;
import com.domain.myenum.OrderStatusEnum;
import com.domain.myenum.PayStatusEnum;
import com.domain.myenum.ProductUnitEnum;
import com.domain.page.Paginator;
import com.dto.CompanyExtDto;
import com.dto.OrderExtDto;
import com.dto.statistic.NameValueDto;
import com.dto.statistic.StatisticOutDto;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.handler.email.Email;
import com.handler.email.EmailHandler;
import com.mapper.generator.ShIncomeWaterMapper;
import com.mapper.generator.ShOrderMapper;
import com.mapper.self.CompanyMapper;
import com.mapper.self.IncomeWaterMapper;
import com.mapper.self.OrderMapper;
import com.mapper.self.ProductMapper;
import com.pojo.ShCompany;
import com.pojo.ShIncomeWater;
import com.pojo.ShOrder;
import com.utils.ConfigUtils;
import com.utils.DateUtils;
import com.utils.RandomUtils;
import com.utils.ValidatorUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Administrator on 2016/2/18 0018.
 */
@Service
public class OrderServiceImpl implements OrderService {


  @Autowired
  private ShOrderMapper shOrderMapper;
  @Autowired
  private OrderMapper orderMapper;
  @Autowired
  private EmailHandler emailHandler;
  @Autowired
  private CompanyMapper companyMapper;
  @Autowired
  private ProductMapper productMapper;
  @Autowired
  private ShIncomeWaterMapper shIncomeWaterMapper;
  @Autowired
  private IncomeWaterMapper incomeWaterMapper;

  @Override
  public Object add(int productId, String email, int count, String sendtime, BigDecimal amount, BigDecimal originalCost, Integer deliveryType, String sendAddr, String remark) {
    // - 验证客户资料是否完善：手机号，送货地址
    Date sendDate = addOrderValiate(email, sendtime, deliveryType, sendAddr);
    ShOrder shOrder = new ShOrder();
    shOrder.setCompanyEmail(email);
    shOrder.setProductId(productId);
    shOrder.setCount(count);
    shOrder.setAmount(amount);
    shOrder.setOriginalCost(originalCost);
    shOrder.setPayStatus(String.valueOf(PayStatusEnum.NotPay.getCode()));
    shOrder.setStatus(String.valueOf(OrderStatusEnum.Wait.getCode()));
    shOrder.setDeleted(0);
    shOrder.setCreatetime(new Date());
    shOrder.setSendtime(sendDate);
    // - 设置Bigdecimal的精度
    shOrder.getAmount().setScale(2);
    // - 设置订单编号
    shOrder.setOrderNo(RandomUtils.getOrderCode());
    shOrder.setDeliveryType(deliveryType.toString());
    shOrder.setSendAddr(sendAddr);
    shOrder.setRemark(remark);
    shOrderMapper.insertSelective(shOrder);
    OrderExtDto orderExtDto = orderMapper.queryByOrderNo(shOrder.getOrderNo());
    mailNotifySalersOrderStatusChanged(orderExtDto, "新订单通知");
    return HttpResponse.create(Codes.OK, "", shOrder.getOrderNo());
  }

  private Date addOrderValiate(String email, String sendtime, Integer deliveryType, String sendAddr) {
    if (StringUtils.isBlank(email)) {
      throw BizException.create(Codes.SystemDeclare, "邮箱为空");
    }
    ShCompany shCompany = companyMapper.queryByEmail(email);
    if (shCompany == null) {
      throw BizException.create(Codes.SystemDeclare, "没有查询到客户信息");
    }
    if (!ValidatorUtils.validatorMobile(shCompany.getPhone())) {
      throw BizException.create(Codes.SystemDeclare, "没有查询到手机号");
    }
    Date sendDate = DateUtils.parseDate("yyyy-MM-dd HH:mm:ss", sendtime + ":00");
    if (sendDate.compareTo(new Date()) < 0) {
      throw BizException.create(Codes.SystemDeclare, "取货时间不得早于当前时间");
    }
    if (deliveryType == null) {
      throw BizException.create(Codes.SystemDeclare, "选择取货方式");
    }
    if (deliveryType == 2) {
      // - 送货上门
      if (StringUtils.isBlank(sendAddr)) {
        throw BizException.create(Codes.SystemDeclare, "填写送货地址");
      }
    }
    return sendDate;
  }

  private void mailNotifySalersOrderStatusChanged(OrderExtDto orderExtDto, String subject) {
    if (StringUtils.isNotBlank(orderExtDto.getShopEmail())) {
      orderNotifyEmail(orderExtDto, subject, Sets.newHashSet(orderExtDto.getShopEmail()));
    }
  }


  /**
   * 订单邮件通知
   *
   * @param orderExtDto 订单信息
   * @param subject     邮件主题
   */
  @Override
  public void orderNotifyEmail(OrderExtDto orderExtDto, String subject, Set<String> emailSet) {
    if (orderExtDto == null) {
      return;
    }
    // - 客户信息
    ShCompany shCompany = companyMapper.queryByEmail(orderExtDto.getEmail());
    String[] to = emailSet.toArray(new String[emailSet.size()]);
    Map<String, Object> map = Maps.newHashMap();
    map.put("buyer", shCompany.getName());
    map.put("mobile", shCompany.getPhone());
    map.put("deliveryType", DeliveryTypeEnum.queryStatusVal(Integer.valueOf(orderExtDto.getDeliveryType())));
    map.put("goodName", orderExtDto.getProductName());
    map.put("price", orderExtDto.getPrice() + "元/" + ProductUnitEnum.queryStatusVal(Integer.parseInt(orderExtDto.getUnit())));
    map.put("count", orderExtDto.getCount() + "/" + ProductUnitEnum.queryStatusVal(Integer.parseInt(orderExtDto.getUnit())));
    map.put("shopName", orderExtDto.getShopName());
    map.put("amount", orderExtDto.getAmount() + "元");
    map.put("remark", StringUtils.isBlank(orderExtDto.getOrderRemark()) ? "无" : orderExtDto.getOrderRemark());
    map.put("sendTime", DateUtils.getFormatDate("yyyy-MM-dd HH:mm:ss", orderExtDto.getSendtime()));
    map.put("reason", orderExtDto.getReason());
    map.put("address", orderExtDto.getSendAddr());
    map.put("subject", subject);
    Email e = new Email();
    e.setTo(to);
    e.setSubject(subject);
    e.setEnableHtml(Boolean.TRUE);
    if (Integer.parseInt(orderExtDto.getDeliveryType()) == DeliveryTypeEnum.GetBySelf.getCode()) {
      e.setTemplate("BookOrderTemplate.ftl");
    }
    if (Integer.parseInt(orderExtDto.getDeliveryType()) == DeliveryTypeEnum.SendHome.getCode()) {
      e.setTemplate("SendOrderTemplate.ftl");
    }
    e.setMap(map);
    emailHandler.asyncSendMail(e);
  }


  @Override
  public Object list(int page, int limit, String email) {
    if (page > 0) {
      page = page - 1;
    }
    List<OrderExtDto> list = orderMapper.list(page * limit, limit, email);
    Paginator paginator = Paginator.instance(orderMapper.count(email), list);
    paginator.setPage(page + 1);
    return paginator;
  }


  @Override
  public Object orderManage(int page, int limit, String email) {
    if (page > 0) {
      page = page - 1;
    }
    List<OrderExtDto> list = orderMapper.orderManage(page * limit, limit, email);
    Paginator paginator = Paginator.instance(orderMapper.orderMgrCount(), list);
    paginator.setPage(page + 1);
    return paginator;
  }

  @Override
  public Object dealOrder(String orderNo, Integer status, String reason) {
    if (StringUtils.isBlank(orderNo)) {
      return HttpResponse.create(Codes.ParamError, "没有查询到订单");
    }
    // - 订单状态不可逆转验证
    OrderExtDto orderExtDto = orderMapper.queryByOrderNo(orderNo);
    if (orderExtDto == null) {
      return HttpResponse.create(Codes.ParamError, "没有查询到订单");
    }
    if (StringUtils.isNotBlank(orderExtDto.getStatus())) {
      if (status.intValue() == OrderStatusEnum.Canceled.getCode()) {
        // - 取消订单
        if (Integer.parseInt(orderExtDto.getStatus()) != OrderStatusEnum.Wait.getCode()) {
          // - 订单不出在等待状态不可取消
          return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，不可撤单");
        }
      }
      if (status.intValue() == OrderStatusEnum.Refused.getCode()) {
        // - 拒绝订单
        if (Integer.parseInt(orderExtDto.getStatus()) != OrderStatusEnum.Wait.getCode()) {
          // - 订单不出在等待状态不可拒绝
          return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，不可拒绝");
        }
      }
      if (status.intValue() <= Integer.parseInt(orderExtDto.getStatus())) {
        return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，状态不可逆转");
      }
    }
    int ret = orderMapper.updateOrderStatus(Lists.newArrayList(orderNo), status, reason);
    // - 完成订单
    if (status.intValue() == OrderStatusEnum.Finished.getCode()) {
      // - 如果订单状态变成完成，将积分累加
      companyMapper.incrUserCredits(orderExtDto.getEmail(), orderExtDto.getAmount());
      // - 商品销量增加，库存减少
      productMapper.updateProductSalesAndInventory(orderExtDto.getCount(), orderExtDto.getProductId());
      // - 记录我的和推荐人的收益流水。
      Boolean isDivideZero = Boolean.FALSE;
      if (orderExtDto.getPrice().compareTo(orderExtDto.getOriginalPrice()) != 0) {
        // - 如果原价和售价一样不记录推荐人流水
        isDivideZero = Boolean.TRUE;
      }
      BigDecimal income = orderExtDto.getAmount()
        .subtract(orderExtDto.getOriginalCost())
        .multiply(BigDecimal.valueOf(ConfigUtils.getDouble("SellerDivide")))
        .setScale(2, BigDecimal.ROUND_HALF_UP);
      recordIncomeWater(isDivideZero,orderExtDto.getCompanyName(), orderExtDto.getEmail(), income, orderExtDto.getProductName(), orderExtDto.getProductId(), orderExtDto.getShopName());

    }
    // - 订单状态变更，邮件通知
    orderExtDto.setStatus(status.toString());
    orderExtDto.setReason(reason);
    // - 邮件收信人
    Set<String> emails = Sets.newHashSet();
    if (status.intValue() == OrderStatusEnum.Accepted.getCode() || status.intValue() == OrderStatusEnum.Refused.getCode()) {
      // - 商家接单/拒绝发邮件通知买家
      emails.add(orderExtDto.getEmail());
      orderNotifyEmail(orderExtDto, "订单状态变更：" + OrderStatusEnum.queryStatusVal(Integer.parseInt(orderExtDto.getStatus())), emails);
    }
    if (status.intValue() == OrderStatusEnum.Canceled.getCode()) {
      // - 用户撤单，邮件通知卖家
      mailNotifySalersOrderStatusChanged(orderExtDto, "用户撤单通知");
    }
    return HttpResponse.OK();
  }

  // - 收益记录流水，同时记录自己和推荐人
  public void recordIncomeWater(Boolean isDivideZero, String buyer, String email, BigDecimal income, String productName, Integer productId, String shopName) {
    CompanyExtDto companyExtDto = companyMapper.queryCompanyExtByEmail(email);
    Date date = new Date();
    if (StringUtils.isBlank(companyExtDto.getReferralEmail()) || isDivideZero) {
      // - 没有推荐人
      ShIncomeWater shIncomeWater = new ShIncomeWater();
      shIncomeWater.setCreateTime(date);
      shIncomeWater.setEmail(email);
      shIncomeWater.setProductId(productId);
      shIncomeWater.setIncome(income);
      shIncomeWater.setReason("消费[" + productName + "]产生收益");
      shIncomeWaterMapper.insertSelective(shIncomeWater);
      companyMapper.addIncome(email, income);
    } else {
      List<ShIncomeWater> incomeWaters = Lists.newArrayList();
      ShIncomeWater shIncomeWater = new ShIncomeWater();
      shIncomeWater.setCreateTime(date);
      shIncomeWater.setEmail(email);
      shIncomeWater.setProductId(productId);
      shIncomeWater.setIncome(income.multiply(BigDecimal.valueOf(ConfigUtils.getDouble("BuyerDivide"))).setScale(2, BigDecimal.ROUND_HALF_UP));
      shIncomeWater.setReason("消费[" + productName + "]产生收益");
      incomeWaters.add(shIncomeWater);
      ShIncomeWater shIncomeWater1 = new ShIncomeWater();
      shIncomeWater1.setCreateTime(date);
      shIncomeWater1.setProductId(productId);
      shIncomeWater1.setIncome(income.multiply(BigDecimal.valueOf(ConfigUtils.getDouble("InviteDivide"))).setScale(2, BigDecimal.ROUND_HALF_UP));
      shIncomeWater1.setEmail(companyExtDto.getReferralEmail());
      shIncomeWater1.setReason("邀请人：" + buyer + "，消费：" + productName + "提成");
      incomeWaters.add(shIncomeWater1);
      incomeWaterMapper.batchInsert(incomeWaters);
      companyMapper.addIncome(email, income.multiply(BigDecimal.valueOf(ConfigUtils.getDouble("BuyerDivide"))).setScale(2, BigDecimal.ROUND_HALF_UP));
      companyMapper.addIncome(companyExtDto.getReferralEmail(), income.multiply(BigDecimal.valueOf(ConfigUtils.getDouble("InviteDivide"))).setScale(2, BigDecimal.ROUND_HALF_UP));
      // - 邮件通知推荐人
      notifyReferralIncomeChangeByEmail(shIncomeWater1.getEmail(), shIncomeWater1.getIncome(), companyExtDto.getReferralName(), productName, shopName, date);
    }
  }


  // - 邮件通知推荐人收益更新
  @Override
  public void notifyReferralIncomeChangeByEmail(String email, BigDecimal income, String referralName, String productName, String shopName, Date time) {
    String[] to = new String[1];
    to[0] = email;
    Email e = new Email();
    e.setTo(to);
    e.setSubject("收益到账通知");
    e.setEnableHtml(Boolean.TRUE);
    Map<String, Object> map = Maps.newHashMap();
    map.put("income", "1.50元");
    map.put("source", "alisa.wang");
    map.put("shop", "老马家面馆");
    map.put("good", "一碗香");
    map.put("time", DateUtils.getFormatDate(null, time));
    e.setMap(map);
    e.setTemplate("incomeTemplate.ftl");
    emailHandler.asyncSendMail(e);
  }

  @Override
  public StatisticOutDto statisticSales(String email) {
    StatisticOutDto dto = new StatisticOutDto();
    if (StringUtils.isBlank(email) || "null".equals(email)) {
      HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
      email = request.getSession().getAttribute("email").toString();
    }
    if (email == null) {
      return dto;
    }
    List<NameValueDto> nameValueDtos = productMapper.queryProductSalesByShopEmail(email.toString());
    List<String> xAixs = Lists.newArrayList();
    List<Integer> yAixs = Lists.newArrayList();
    if (CollectionUtils.isEmpty(nameValueDtos)) {
      return dto;
    }
    for (NameValueDto nameValueDto : nameValueDtos) {
      xAixs.add(nameValueDto.getName());
      yAixs.add(nameValueDto.getValue());
    }
    dto.setxAixs(xAixs);
    dto.setyAixs(yAixs);
    return dto;
  }
}
